#pragma once

#include "hugin"
#include <list>
#include <cstdlib>
#include <iostream>
#include <ctime> 
#include "ExpandTimeSteps.h"
#include <hash_map>
#include <fstream>
#include <sstream>


using namespace HAPI;
using namespace std;
using namespace stdext;

struct DidResult
{
	string model;
	int timeStep;
	string state;
	string observation;
	string action;
	double utility;
};

struct IDidResult
{
	int timeStep;
	string oponentModel;
	string state;
	string observation;
	string action;
	string oponentAction;
	double utility;
};

struct DIDTimeStepNodes
{
	DiscreteNode * stateNode;
	DiscreteNode * observationNode;
	DiscreteDecisionNode * decisionNode;
	UtilityNode * utilityNode;
};

struct IDIDTimeStepNodes
{
	DiscreteNode * stateNode;
	DiscreteNode * observationNode;
	DiscreteNode * oponentActionNode;
	DiscreteDecisionNode * decisionNode;
	UtilityNode * utilityNode;
	DiscreteNode * modelNode;
};

class Simulator
{
private:
	Node* Simulator::FindNodeWithPrefix(NodeList nodes, string prefix);
	int Simulator::ChooseRandomStateForNode(DiscreteNode * node);
	int Simulator::ChooseDecisionForNode(DiscreteDecisionNode * node);
	Domain * Simulator::ChooseRandomModel(list<Domain*> models);
	DIDTimeStepNodes Simulator::GetDIDNodesForTimeStep(Domain * inputID, int timeStep, string statePrefix, string observationPrefix, string decisionPrefix, string utilityPrefix);
	IDIDTimeStepNodes Simulator::GetIDIDNodesForTimeStep(Domain * inputID, int timeStep, string statePrefix, string observationPrefix, string decisionPrefix, string utilityPrefix, string jActionPrefix, string modelPrefix);
	void Simulator::ResetNodes(hash_map<string, int> nodes, Domain * inputID);
	void Simulator::ClearNodes(hash_map<string, int> nodes, Domain * inputID);
	void Simulator::SetNodeFindings(DiscreteNode * node, int state);
	void Simulator::ApplyModelWeighting(DiscreteNode * modelNode);

	int currentModel;

public:
	__declspec(dllexport) Simulator(void);
	__declspec(dllexport) list<DidResult> Simulator::SimulateDID(list<Domain*> inputModels, string statePrefix, string observationPrefix, 
														string actionPrefix, string utilityPrefix, int numberOfSimulations);

	__declspec(dllexport) list<IDidResult> Simulator::SimulateIDID(Domain * inputIdid, list<Domain*> inputModels, string statePrefix, string utilityPrefix,
														string iObservationPrefix, string jObservationPrefix, string iActionPrefix, string jActionPrefix,
														int numberOfSimulations, bool modelWeighting, string modelPrefix);

	__declspec(dllexport) void Simulator::SaveDIDToCsvFile(list<DidResult>results, string fileName);
	__declspec(dllexport) void Simulator::SaveIDIDToCsvFile(list<IDidResult>results, string fileName);
};

